
#include "stdafx.h"
#include "hdict.h"
#include <windows.h>

#define IS_UPPER(x)			((x) >= 'A' && (x) <= 'Z')
#define IS_LOWER(x)			((x) >= 'a' && (x) <= 'z')
#define IS_DIGIT(x)			((x) >= '0' && (x) <= '9')
#define IS_PINYIN_ALPHA(x)	(IS_UPPER(x) || IS_LOWER(x))
#define IS_WHITESPACE(x)	(x == ' ' || x == '\t')
#define IS_NEWLINE(x)		(x == '\r' || x =='\n')

BOOL HanzDict::Init( CString const& strDictFile )
{
	HANDLE hFile = CreateFile(strDictFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (INVALID_HANDLE_VALUE != hFile)
	{
		DWORD dwSize = GetFileSize(hFile, NULL);
		const int charcount = dwSize / 2 + 1;
		WCHAR* szBuffer = new WCHAR[charcount];
		ZeroMemory(szBuffer, charcount * sizeof(WCHAR));
		DWORD r = 0;
		BOOL bRead = ReadFile(hFile, szBuffer, dwSize + 2, &r, NULL);
		CloseHandle(hFile);

		InitMap(szBuffer);
		return TRUE;
	}
	return FALSE;
}

#define PINYINMAX		16
#define HANZLINEMAX		2048

BOOL HanzDict::InitMap(LPCWSTR szBuffer)
{
	const WCHAR* p = szBuffer;
	WCHAR szPinyin[PINYINMAX] = {};
	WCHAR szHanzLine[HANZLINEMAX] = {};
	int iPinyinOffset = 0;
	int iHanzOffset = 0;
	BOOL bScanHanz = FALSE;
	while (*p)
	{
		WCHAR ch = *p;
		if (IS_PINYIN_ALPHA(ch))
		{
			szPinyin[iPinyinOffset] = ch;
			iPinyinOffset++;
			p++;
			continue;
		}
		else if (IS_WHITESPACE(ch))
		{
			p++;
			bScanHanz = TRUE;
			continue;
		}
		else if (IS_NEWLINE(ch))
		{
			m_hanz[szPinyin] = szHanzLine;
			bScanHanz = FALSE;
			iPinyinOffset = 0;
			iHanzOffset = 0;
			ZeroMemory(szPinyin, PINYINMAX * 2);
			ZeroMemory(szHanzLine, HANZLINEMAX * 2);
			p++;
			continue;
		}
		else if (bScanHanz)
		{
			szHanzLine[iHanzOffset] = ch;
			iHanzOffset++;
			p++;
			continue;
		}

		else
		{
			p++;
		}
	}
	return TRUE;
}

CString HanzDict::GetPinyin( CString const& strText )
{
	CString strPinyin;
	UINT nCount = strText.GetLength();
	for (int i = 0; i < (int)nCount; ++i)
	{
		strPinyin += "[";
		WCHAR hanzi = strText[i];
		if (IS_UPPER(hanzi) || IS_LOWER(hanzi) || IS_DIGIT(hanzi))
		{
			strPinyin += hanzi;
		}
		else
		{
			map<CString, CString>::const_iterator iter = m_hanz.begin();
			for (; m_hanz.end() != iter; ++iter)
			{
				if (iter->second.Find(hanzi) >= 0)
				{
					strPinyin += iter->first;
					break;
				}
			}
		}

		strPinyin += "]";
	}
	return strPinyin;
}